Деплой на VPS — Docker + Traefik
Версия: 1.0 Дата: 21.04.2026 Статус: Утверждён
Руководство описывает полный цикл развёртывания статического сайта документации на VPS с Docker и Traefik как обратным прокси. Этот вариант не требует Node.js или pm2 на сервере — доставляется только готовая сборка. Дополнительно описан альтернативный метод через pm2 + nginx.
Архитектура
Локальная машина VPS
───────────────── ───────────────────────────────────
docs/ ~/docs/
├── build/ ── rsync ──► ├── build/ (статика)
└── docker-compose ── rsync ──► └── docker-compose.yml
│
Docker: nginx:alpine
│ подключён к сети proxy
│
Traefik (уже работает)
│
HTTPS :443 → браузер
При деплое:
- Локально собирается статический HTML (
npm run build) build/иdocker-compose.ymlкопируются на сервер через rsync по SSH- На сервере поднимается контейнер nginx с примонтированным
build/ - Traefik обнаруживает контейнер по labels и начинает маршрутизацию
Требования
На локальной машине
- Node.js, npm — для сборки
rsync,ssh— для деплоя- SSH-ключ без пароля (BatchMode)
На сервере
- Docker + Docker Compose
- Traefik v2/v3 запущен в Docker с внешней сетью
proxy - SSH-доступ по ключу
Подготовка — один раз
1. SSH-ключ для деплоя
Скрипты работают в BatchMode — без интерактивного ввода пароля. Нужен отдельный ключ.
# Сгенерировать ключ
ssh-keygen -t ed25519 -f ~/.ssh/vps-vlad -C "docs-deploy"
# В WSL нет GUI — используем sshpass для копирования ключа
sudo apt-get install -y sshpass
sshpass -p 'пароль' ssh-copy-id -o StrictHostKeyChecking=accept-new -i ~/.ssh/vps-vlad.pub -p 22 vlad@85.214.181.52
# Проверить BatchMode
ssh -o BatchMode=yes -i ~/.ssh/vps-vlad -p 22 vlad@85.214.181.52 "echo ok"
# Должно вывести: ok
Опционально — добавить в ~/.ssh/config:
Host vps-vlad
HostName 85.214.181.52
User vlad
Port 22
IdentityFile ~/.ssh/vps-vlad
IdentitiesOnly yes
2. Настроить cms-config.json
"vps": {
"domain": "85.214.181.52",
"ssh_host": "vlad@85.214.181.52",
"ssh_port": 22,
"ssh_key": "~/.ssh/vps-vlad",
"remote_path": "/home/vlad/docs",
"deploy_method": "docker",
"pm2_app": ""
}
| Поле | Описание |
|---|---|
domain | Домен или IP — используется в выводе после деплоя |
ssh_host | user@host для SSH |
ssh_port | SSH порт (обычно 22) |
ssh_key | Путь к приватному ключу (если пусто — использует агент) |
remote_path | Папка на сервере куда деплоится проект |
deploy_method | docker или pm2 — метод деплоя |
pm2_app | Имя pm2-процесса (только для метода pm2) |
3. Создать папку на сервере
ssh vlad@85.214.181.52 "mkdir -p ~/docs/build"
4. Проверить сеть Traefik на сервере
ssh vlad@85.214.181.52 "docker network ls | grep proxy"
Должна быть сеть с именем proxy. Если нет — уточни имя сети и поправь docker-compose.vps.yml.
Конфигурация контейнера
Файл docker-compose.vps.yml в корне репозитория:
services:
docs:
image: nginx:alpine
restart: unless-stopped
volumes:
- ./build:/usr/share/nginx/html:ro
networks:
- proxy
labels:
- traefik.enable=true
- traefik.docker.network=proxy
- traefik.http.routers.docs.rule=Host(`85.214.181.52`)
- traefik.http.routers.docs.entrypoints=websecure
- traefik.http.routers.docs.tls=true
- traefik.http.services.docs.loadbalancer.server.port=80
networks:
proxy:
external: true
| Параметр | Назначение |
|---|---|
nginx:alpine | Лёгкий веб-сервер для раздачи статики |
./build:/usr/share/nginx/html:ro | Монтируем сборку только для чтения |
networks: proxy | Подключаемся к сети Traefik |
traefik.enable=true | Разрешаем Traefik управлять контейнером |
Host(...) | Правило маршрутизации по домену или IP |
entrypoints=websecure | Слушаем на порту 443 (HTTPS) |
tls=true | TLS терминируется на Traefik |
HTTPS по IP: При доступе по голому IP без домена Traefik выдаёт самоподписанный сертификат. Браузер покажет предупреждение — нажать «Продолжить» / «Перейти». После привязки домена предупреждение исчезнет (Let's Encrypt).
Деплой
Через панель управления (Tools UI)
Открыть http://localhost:3000/admin/tools.html → раздел «Публикация» → кнопка VPS · docker.
Из командной строки
tools/deploy_site.sh --mode=vps
Метод берётся из cms-config.json → vps.deploy_method. Переопределить явно:
tools/deploy_site.sh --mode=vps --method=docker
tools/deploy_site.sh --mode=vps --method=pm2
Что делает скрипт (метод docker)
- sync_assets — синхронизация медиафайлов из
docs/*/assets/вstatic/ - build_index — обновление главной страницы
- npm run build — сборка статического HTML в
build/ - SSH check — проверка соединения с сервером
- rsync
build/→remote_path/build/на сервере - rsync
docker-compose.vps.yml→remote_path/docker-compose.yml - docker compose up -d — поднимает или перезапускает контейнер
Добавление домена или поддомена
Шаг 1. DNS-запись
В панели DNS вашего регистратора добавить A-запись:
docs.yourdomain.com A 85.214.181.52
# или поддомен:
api.yourdomain.com A 85.214.181.52
Изменения DNS распространяются от нескольких минут до 24 часов в зависимости от TTL.
Шаг 2. Обновить cms-config.json
"vps": {
"domain": "docs.yourdomain.com",
...
}
Шаг 3. Обновить docker-compose.vps.yml
Заменить правило маршрутизации и добавить certresolver:
labels:
- traefik.enable=true
- traefik.docker.network=proxy
- traefik.http.routers.docs.rule=Host(`docs.yourdomain.com`)
- traefik.http.routers.docs.entrypoints=websecure
- traefik.http.routers.docs.tls=true
- traefik.http.routers.docs.tls.certresolver=letsencrypt
- traefik.http.services.docs.loadbalancer.server.port=80
Строка tls.certresolver=letsencrypt — Traefik автоматически получит сертификат Let's Encrypt. Имя резолвера должно совпадать с тем, что настроено в конфиге Traefik.
Шаг 4. Задеплоить
tools/deploy_site.sh --mode=vps --method=docker
Несколько сайтов на одном сервере
Каждый сайт — отдельный docker-compose.yml с уникальным именем роутера:
# Первый сайт
- traefik.http.routers.docs.rule=Host(`docs.yourdomain.com`)
# Второй сайт (в другом compose-файле)
- traefik.http.routers.api-docs.rule=Host(`api.yourdomain.com`)
Имена роутеров (docs, api-docs) должны быть уникальными в пределах Traefik.
Проверка сертификата
# Логи Traefik — должен появиться ACME-запрос
ssh vlad@85.214.181.52 "docker logs traefik 2>&1 | grep -i acme"
# Проверить сертификат
curl -I https://docs.yourdomain.com
Настройка Traefik на сервере
Этот раздел — для справки на случай если Traefik ещё не настроен.
docker-compose.yml для Traefik
services:
traefik:
image: traefik:v3
restart: unless-stopped
command:
- --providers.docker=true
- --providers.docker.exposedByDefault=false
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --entrypoints.web.http.redirections.entryPoint.to=websecure
- --entrypoints.web.http.redirections.entryPoint.scheme=https
# Раскомментировать для Let's Encrypt:
# - --certificatesResolvers.letsencrypt.acme.email=you@example.com
# - --certificatesResolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
# - --certificatesResolvers.letsencrypt.acme.tlsChallenge=true
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
# - ./letsencrypt:/letsencrypt # нужно для хранения сертификатов
networks:
- proxy
networks:
proxy:
external: true
Создать внешнюю сеть один раз:
docker network create proxy
Деплой через pm2 + nginx (альтернатива)
Если на сервере нет Docker или предпочтителен pm2.
Требования на сервере
# Node.js
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs
# pm2 и serve
sudo npm install -g pm2 serve
cms-config.json для pm2
"vps": {
"deploy_method": "pm2",
"pm2_app": "docs",
"remote_path": "/home/vlad/docs",
...
}
Первоначальная настройка на сервере
ssh vlad@85.214.181.52
mkdir -p ~/docs/build
cd ~/docs
# Запустить serve как pm2-процесс
pm2 start serve --name docs -- build -p 3000
pm2 save
pm2 startup # скопировать и выполнить команду которую выведет pm2
Деплой
tools/deploy_site.sh --mode=vps --method=pm2
Скрипт выполняет rsync build/ → сервер, затем pm2 restart docs.
nginx как обратный прокси (для pm2)
sudo apt-get install -y nginx
sudo nano /etc/nginx/sites-available/docs
server {
listen 80;
server_name docs.yourdomain.com;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
sudo ln -s /etc/nginx/sites-available/docs /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
# SSL через certbot
sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d docs.yourdomain.com
Диагностика
Проверить что контейнер запущен
ssh vlad@85.214.181.52 "cd ~/docs && docker compose ps"
Посмотреть логи контейнера
ssh vlad@85.214.181.52 "cd ~/docs && docker compose logs --tail=50"
Проверить что Traefik видит контейнер
ssh vlad@85.214.181.52 "docker logs traefik 2>&1 | tail -30"
Принудительно пересоздать контейнер
ssh vlad@85.214.181.52 "cd ~/docs && docker compose down && docker compose up -d"
Только
up -dне пересоздаёт контейнер если он уже существует с другими labels.down && up -dгарантирует применение изменённой конфигурации.
Сравнение методов
| Docker + Traefik | pm2 + nginx | |
|---|---|---|
| Node.js на сервере | Не нужен | Обязателен |
| Обновление сайта | rsync + docker compose up -d | rsync + pm2 restart |
| SSL | Traefik автоматически | certbot вручную |
| Несколько сайтов | Labels в compose-файлах | Отдельные nginx-конфиги |
| Подходит если | Traefik уже есть | Простой сервер без Docker |